import * as calculate from "@/util/xc/calculate";
import { pair } from "../config/config";
import bus from "../eventBus/eventBus";

/**
 * 分部计算
 */
export const calculateEval = n => {
  n = splitFormula(n);
  const result = eval(n);
  console.log(n, result);
  return result == Infinity ? 0 : result || 0;
};

/**
 * 转换公式
 * @param {String} n 真实数值公式
 * @returns {String} 最终计算的公式
 */
function splitFormula(n) {
  console.group("开始遍历计算", n, Object.keys(calculate));
  const arr = Object.keys(calculate);
  var left = [];
  var i = 0;
  while (n[i]) {
    var s = n[i];
    if (s === "(") left.push(i);
    if (s === ")") {
      const ss = left.pop();
      const is = arr.find(k => n.substring(ss - k.length, ss) == k);
      const f = n.substring(ss, i + 1);
      if (is) {
        n = n.replace(is + f, eval(`calculate.${is + f}`) || 0);
      } else {
        const r = evalBrackets(f) || 0;
        n = n.replace(f, r);
        i -= f.length - (r + "").length;
        console.log(n, i, f, r);
      }
    }
    i++;
  }
  console.log(n);
  console.groupEnd();
  return n;
}

/**
 * 括弧内按加号减号计算
 * @param {String} str 最底层括号内公式
 * @returns {Number} 计算结果
 */
function evalBrackets(str) {
  console.group("按加号计算", str);
  const n = str.startsWith("(") ? str.substring(1, str.length - 1) : str;
  const arr = n.split("+").map(item => {
    return addReduce(item.split("-"));
  });
  console.groupEnd();
  return addReduce(arr, true);
}

/**
 * 求和求减
 * @param {Array} arr 数字数组
 * @param {Boolean} isAdd true:加 false: 减
 * @returns {Number} 计算结果
 */
function addReduce(arr, isAdd = false) {
  return arr.reduce((a, b) => {
    const aa = parseValue(a);
    const bb = parseValue(b);
    if (isAdd) return aa + bb;
    else return aa - bb;
  });
}

/**
 * 解析值
 * @param {any} str 需要解析的值
 * @returns {Number} 不能解析的值返回 0
 */
function parseValue(str) {
  if (isNaN(str)) return 0;
  else return Number(str);
}

/**
 * 获取逻辑代码
 * 如果还有对应的逻辑公式会进行递归转换
 * @param {String} name 拼音
 * @param {Object} data 值来源
 * @returns {Number}
 * 1. 如果是逻辑公式返回公式里面返回的值
 * 2. 否则返回0
 */
export const shiftLogicCode = (name, data) => {
  let o = bus.formulaArr.find(item => item.namePy == name)?.formulaDetail;
  if (o) {
    o = toTheValue(o, data);
    o = replaceCalculate(o);
    o = o.replace(/or/g, "||");
    o = o.replace(/and/g, "&&");
    o = shiftDivisor(o);
    const fn = new Function(o).bind(calculate);
    console.group("处理对应逻辑代码", name, bus.formulaArr);
    console.log(fn);
    console.groupEnd();
    return fn() || 0;
  }
  return 0;
};

/** 处理除以0的情况, 改为/ 1 */
export const shiftDivisor = str => {
  const regExp = new RegExp(/\/\s*0/, "g");
  console.groupCollapsed("处理除数为0的情况", regExp, str);
  const arr = str.matchAll(regExp);
  let o = arr.next();
  while (!o.done) {
    const n = o.value[0];
    str = str.replace(n, "/ 1");
    o = arr.next();
  }
  console.log(str);
  console.groupEnd();
  return str;
};

/**
 * 对应函数连接
 * @param {String} str 公式
 * @returns 函数前会加上this
 */
export const replaceCalculate = (str = "") => {
  const arr = Object.keys(calculate);
  arr.forEach(item => {
    const f = "(";
    const regExp = new RegExp(`${item}\\${f}`, "g");
    str = str.replace(regExp, `this.${item + f}`);
  });
  return str;
};

/**
 * 带入值
 * #考勤字段#  |薪酬字段|  [统计字段]
 * @param {String} formula 公式字符串
 * @param {Object} data 值来源
 * @returns {String} 有真实值的公式
 */
export const toTheValue = (formula, data) => {
  console.group("公式带入值", formula, data, bus.dataSource, bus.holidayData);
  let n = formula;

  n = replaceValue(n, /\|.*?\|/g, data, {
    yanglao: data.gryl,
    shiye: data.grsy,
    yiliao: data.gryil,
    gongshang: data.grgs,
    gongjijin: data.personalAf
  });
  n = replaceValue(n, /\[.*?\]/g, data, bus.holidayData[data.userId]);
  n = replaceValue(n, /#.*?#/g, data, bus.holidayData[data.userId]);
  // n = replaceCalculate(n);
  console.log("计算结果", n);
  console.groupEnd();
  return n;
};

/**
 * 带入真实值
 * @param {String} n 公式字符串
 * @param {Object} match 正则查找
 * @param {Object} data 值来源
 * @param {Object} other 其他值来源
 * @returns 根据正则替换完真实值的公式
 */
export const replaceValue = (n, match, data, other) => {
  console.group("开始带入值", match, data, other);
  data = { ...data, ...other };
  const arr = n.match(match) || [];
  console.log(arr);
  arr.forEach(item => {
    const key = item.substr(1, item.length - 2);
    const val = getKeyValue(key, data);
    n = n.replace(item, val);
  });
  console.groupEnd();
  return n;
};

/**
 * 获取对应值
 * @param {String} key 拼音
 * @param {Object} data 值来源
 * @returns 对应拼音的真实值
 */
export const getKeyValue = (key, data) => {
  const result = shiftLogicCode(key, data);
  console.log(key, result);
  const key1 = pair.getDimMatch(key)[0];
  return result || data[key] || data[key1] || 0;
};
